﻿/********************************************************
 * Module Name    : Attachment
 * Purpose        : Contains functions used to upload/download/view/delete attachments 
 *                  of a record from "Attachment" window
 * Class Used     : MAttachmentEntry.cs, X_AD_Attachment.cs
 * Chronological Development
 * Veena Pandey     10-March-2009
 ******************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VAdvantage.Classes;
using System.Data;
//using java.Utility.zip;//Silver doesn't support
//using java.io;//Silver doesn't support
using System.IO;
using VAdvantage.DataBase;
using VAdvantage.Logging;
using VAdvantage.Utility;
using System.Windows.Resources;
using System.Windows;
using System.Runtime.Serialization;
using System.Net.Browser;
using System.Net;

namespace VAdvantage.Model
{
    /// <summary>
    /// A class which contains functions used to upload/download/view/delete attachments
    /// of a record from "Attachment" window
    /// </summary>
    public class MAttachment : X_AD_Attachment
    {
        #region PrivateVAriables
        /**	Static Logger	*/
        private static VLogger _log = VLogger.GetVLogger(typeof(MAttachment).FullName);
        List<MAttachmentEntry> _items = null;
        private const string ZIP = "zip";
        MAttachmentEntry _attchedFileName;
        #endregion

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="ctx">context</param>
        /// <param name="AD_Table_ID">AD_Table_ID</param>
        /// <param name="Record_ID">Record_ID</param>
        /// <param name="trxName">transaction</param>
        public MAttachment(Ctx ctx, int AD_Table_ID, int Record_ID, string trxName)
            : base(ctx, 0, trxName)
        {
            // set table id
            SetAD_Table_ID(AD_Table_ID);
            // set record id
            SetRecord_ID(Record_ID);
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="ctx">context</param>
        /// <param name="AD_Attachment_ID">AD_Attachment_ID</param>
        /// <param name="trxName">transaction</param>
        public MAttachment(Ctx ctx, int AD_Attachment_ID, string trxName)
            : base(ctx, AD_Attachment_ID, trxName)
        {

            if (GetAD_Attachment_ID () >0)
            {
                LoadBinaryItems(AD_Attachment_ID);
            }
        }

        private void LoadBinaryItems(int AD_Attachment_ID)
        {
            bool loading = true;
            string tableName = Get_TableName();
            var client = AEnv.GetDataServiceBasic2Client();
            client.GetAttachmentInfoCompleted += (s, e) =>
                {
                    _items = new List<MAttachmentEntry>();
                    try
                    {
                        // Get binaryData from DB
                        DataServiceBasic2.AttachmentInfo info = e.Result;

                        // if no data, then return
                        if (info == null)
                            return;

                        if (info.AttachmentEntries.Count == 0)
                            return;

                        if (info.AttachmentEntries.Count == 1)
                        {
                            if (!ZIP.Equals(info.AttachmentEntries[0].Name))
                            {
                                _items.Add(new MAttachmentEntry(info.AttachmentEntries[0].Name, info.AttachmentEntries[0].Data, info.AttachmentEntries[0].Index));
                                return;
                            }

                        }


                        for (int i = 0; i < info.AttachmentEntries.Count; i++)
                        {
                            _items.Add(new MAttachmentEntry(info.AttachmentEntries[i].Name, info.AttachmentEntries[i].Data, info.AttachmentEntries[i].Index));
                        }


                        //	Old Format - single file
                    }
                    catch
                    {

                    }

                    finally
                    {
                        loading = false;
                    }
                    
                    


                };
            client.GetAttachmentInfoAsync(AD_Attachment_ID, tableName);
            client.CloseAsync();
            while (loading)
            {
                System.Threading.Thread.Sleep(10);
            }
        }

        /// <summary>
        /// Load Constructor
        /// </summary>
        /// <param name="ctx">context</param>
        /// <param name="rs">result set</param>
        /// <param name="trxName">transaction</param>
        public MAttachment(Ctx ctx, DataRow rs, String trxName)
            : base(ctx, rs, trxName)
        {
            if (GetAD_Attachment_ID() > 0)
            {
                LoadBinaryItems(GetAD_Attachment_ID());
            }
        }

        /// <summary>
        /// Get Attachment
        /// </summary>
        /// <param name="ctx">context</param>
        /// <param name="AD_Table_ID">table id</param>
        /// <param name="Record_ID">record id</param>
        /// <returns>attachment or null</returns>
        public static MAttachment Get(Ctx ctx, int AD_Table_ID, int Record_ID)
        {
            MAttachment retValue = null;
            String sql = "SELECT * FROM AD_Attachment WHERE AD_Table_ID=" + AD_Table_ID + " AND Record_ID=" + Record_ID + "";
            try
            {
                DataSet ds = DB.ExecuteDataset(sql, null, null);
                if (ds.Tables.Count > 0)
                {
                    foreach (DataRow dr in ds.Tables[0].Rows)
                    {
                        retValue = new MAttachment(ctx, dr, null);
                    }
                }
            }
            catch (Exception e)
            {
                _log.Log(Level.SEVERE, sql, e);
            }
            return retValue;
        }

        /// <summary>
        /// Add a new entry
        /// </summary>
        /// <param name="file">file path</param>
        /// <returns>bool type true if file added sucessfully</returns>
        public bool AddEntry(string filePath)
        {
            if (filePath == null)
            {
                log.Warning("No File");
                return false;
            }
            string fullName = filePath;
            string[] splitName = fullName.Split('\\');
            string name = splitName[splitName.Length - 1];

            //Initialize byte array with a null value initially.
            byte[] data = null;
            try
            {
                data = null;
                //Use FileInfo object to get file size.
                System.IO.FileInfo fInfo = new System.IO.FileInfo(filePath);
                long numBytes = fInfo.Length;

                //Open FileStream to read file
                System.IO.FileStream fStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);

                //Use BinaryReader to read file stream into byte array.
                System.IO.BinaryReader br = new System.IO.BinaryReader(fStream);

                //When you use BinaryReader, you need to supply number of bytes to read from file.
                //In this case we want to read entire file. So supplying total number of bytes.
                data = br.ReadBytes((int)numBytes);

            }
            catch (Exception ex)
            {
                log.Log(Level.SEVERE, "(file)", ex);
            }
            return AddEntry(name, data);
        }

        /// <summary>
        /// Add a new entry
        /// </summary>
        /// <param name="name">name of file</param>
        /// <param name="data">data</param>
        /// <returns>bool type true if file added sucessfully</returns>
        public bool AddEntry(string name, byte[] data)
        {
            if (name == null || data == null)
            {
                return false;
            }
            return AddEntry(new MAttachmentEntry(name, data, 0));	//	random number at index 0
        }

        /// <summary>
        /// Add a new entry
        /// </summary>
        /// <param name="item">MAttachment object item</param>
        /// <returns>bool type true if file added sucessfully</returns>
        public bool AddEntry(MAttachmentEntry item)
        {
            if (item == null)
            {
                return false;
            }
            if (_items == null)
            {
                // load data
                LoadLOBData();
            }

            bool retValue = false;

            try
            {
                _items.Add(item);

                retValue = true;
            }
            catch
            { }
            log.Fine(item.ToString());
            AddTextMsg(" ");	//	otherwise not saved
            return retValue;
        }

        /// <summary>
        /// Appends text message to existing text message
        /// </summary>
        /// <param name="added">text message</param>
        public void AddTextMsg(string added)
        {
            string oldTextMsg = GetTextMsg();
            if (oldTextMsg == null)
                SetTextMsg(added);
            else if (added != null)
                SetTextMsg(oldTextMsg + added);
        }

        //public string GetTextMsg()
        //{
        //    string msg = base.GetTextMsg();
        //    if (msg == null)
        //        return null;
        //    return msg.Trim();
        //}

        /// <summary>
        /// Get Entry at specified index
        /// </summary>
        /// <param name="index">index</param>
        /// <returns></returns>
        public MAttachmentEntry GetEntry(int index)
        {
            if (_items == null)
            {
                // load data
                LoadLOBData();
            }
            if (index < 0 || index >= _items.Count)
            {
                return null;
            }
            return (MAttachmentEntry)_items[index];
        }

        public MAttachmentEntry[] GetEntries()
        {
            if (_items == null)
            {
                LoadLOBData();
            }
            MAttachmentEntry[] retValue = new MAttachmentEntry[_items.Count];
            retValue = _items.ToArray();
            return retValue;
        }

        /// <summary>
        /// Remove an entry at given index
        /// </summary>
        /// <param name="index">index</param>
        /// <returns>bool type true if removed successfully</returns>
        public bool DeleteEntry(int index)
        {
            if (_items == null)
            {
                // load data
                LoadLOBData();
            }
            if (index >= 0 && index < _items.Count)
            {
                // remove entry
                _items.RemoveAt(index);
                log.Config("Index=" + index + " - NewSize=" + _items.Count);
                return true;
            }
            log.Warning("Not deleted Index=" + index + " - Size=" + _items.Count);
            return false;
        }

        /// <summary> 
        /// Get total number of entries
        /// </summary>
        /// <returns>int</returns>
        public int GetEntryCount()
        {
            if (_items == null)
            {
                // load data
                LoadLOBData();
            }
            if (_items == null)
                return 0;
            return _items.Count;
        }

        /// <summary>
        /// Get file name of the entry at given index
        /// </summary>
        /// <param name="index">index</param>
        /// <returns>string</returns>
        public string GetEntryName(int index)
        {
            // get item
            MAttachmentEntry item = GetEntry(index);
            // get name
            if (item != null)
                return item.GetName();
            return null;
        }

        /// <summary>
        /// Get file data of the entry at given index
        /// </summary>
        /// <param name="index">index</param>
        /// <returns>byte[] data</returns>
        public byte[] GetEntryData(int index)
        {
            // get item
            MAttachmentEntry item = GetEntry(index);
            // get data
            if (item != null)
                return item.GetData();
            return null;
        }

        /// <summary>
        /// Saves the file at given index to harddisk at given path
        /// </summary>
        /// <param name="index">index</param>
        /// <param name="filePath">file path</param>
        public void SaveEntryFile(int index, string filePath)
        {
            // get item
            MAttachmentEntry item = GetEntry(index);
            // save file
            if (item != null)
                item.SaveFile(filePath);
        }


        /// <summary>
        /// Saves the file at given index to harddisk at given path
        /// </summary>
        /// <param name="index">index</param>
        /// <param name="filePath">file path</param>
        public void SaveEntryFile(int index, string filePath,Stream s)
        {
            // get item
            MAttachmentEntry item = GetEntry(index);
            // save file
            if (item != null)
                item.SaveFile(filePath,s);
        }


        /// <summary>
        /// This function is called before final saving of records
        /// </summary>
        /// <returns>bool type true if can be saved</returns>
        protected override bool BeforeSave(bool newRecord)
        {
            if (GetTitle() == null || !GetTitle().Equals(ZIP))
                SetTitle(ZIP);
            //	save in BinaryData
            return SaveLOBData();
        }

        /// <summary>
        /// Save Entry Data in Zip File format
        /// </summary>
        /// <returns>bool type true if saved</returns>
        private bool SaveLOBData()
        {
           
            if (_items == null || _items.Count == 0 )
            {
                SetBinaryData(null);
                return true;
            }

            int upperLimit = 25*1024*1024;

            int length = 0;
            int isize = _items.Count;
            for (int i = 0; i < isize; i++)
            {
                length += _items[i].GetData().Length;
            }

            if (length > upperLimit)
            {
                 System.Windows.Deployment.Current.Dispatcher.BeginInvoke(()=>Classes.ShowMessage.Warn("Warn?",true, Msg.GetMsg("FileSizeLimit"),""));
                return false;
            }
            ////ByteArrayOutputStream bOut = new ByteArrayOutputStream();//silverlight comment
            //MemoryStream bOut = new MemoryStream();
            //ZipOutputStream zip = new ZipOutputStream(bOut);//silverlight comment
            //zip.setMethod(ZipOutputStream.DEFLATED);//silverlight comment
            //zip.setLevel(Deflater.BEST_COMPRESSION);//silverlight comment

            //try
            //{
            //    // for every item in list
            //    int isize = _items.Count;
            //    for (int i = 0; i < isize; i++)
            //    {
            //        // get item
            //        MAttachmentEntry item = GetEntry(i);
            //        // make zip entry
            //        ZipEntry entry = new ZipEntry(item.GetName());//silverlight comment
            //        // set time
            //        entry.setTime(long.Parse(System.DateTime.Now.Millisecond.ToString()));//silverlight comment
            //        entry.setMethod(ZipEntry.DEFLATED);//silverlight comment
            //        // start setting zip entry into zip file
            //        zip.putNextEntry(entry);//silverlight comment
            //        data = item.GetData();
            //        object obj = (object)data;
            //        // set data into zip
            //        zip.write((byte[])obj, 0, data.Length);//silverlight comment
            //        // close zip entry
            //        zip.closeEntry();//silverlight comment
            //    }
            //    // close zip
            //    zip.close();//silverlight comment

            //   byte[] sObjData = bOut.toByteArray();//silverlight comment
            //     byte[] zipData = ConvertToByte(sObjData);//silverlight comment

            //    log.Fine("Length=" + zipData.Length);//silverlight comment

            //    // Set binary data in PO and return
            //    SetBinaryData(zipData);//silverlight comment
            //    SetBinaryData(data);
            //    return true;
            //}
            //catch (Exception ex)
            //{
            //    log.Log(Level.SEVERE, "saveLOBData", ex);
            //}
            //// Set binary data in PO and return
            
            SetBinaryData(null);
            
            return true;
        }

        protected override bool AfterSave(bool newRecord, bool success)
        {
            if ((_items == null || _items.Count == 0) && !this.IsFileSystem())
            {
                //SetBinaryData(null);
               // return true;
            }

            DataServiceBasic2.AttachmentInfo aInfo = new DataServiceBasic2.AttachmentInfo();
            aInfo.AttachmentEntries = new List<DataServiceBasic2.AttachmentEntry>();

             int isize = _items.Count;
             for (int i = 0; i < isize; i++)
             {
                 MAttachmentEntry mEntry = _items[i];

                 DataServiceBasic2.AttachmentEntry entry = new DataServiceBasic2.AttachmentEntry();
                 entry.Name = mEntry.GetName();
                 entry.Data = mEntry.GetData();
                 entry.Index = mEntry.GetIndex();
                 aInfo.AttachmentEntries.Add(entry);
             }

             bool saving = true;


             var client = AEnv.GetDataServiceBasic2Client();
             client.SetAttachmenInfoCompleted += (s, e) =>
                 {
                     if (!e.Result)
                     {
                         //Log.Log(Error);
                     }

                     saving = false;

                 };
             client.SetAttachmenInfoAsync(aInfo, this.GetAD_Attachment_ID(),this.Get_TableName());
             client.CloseAsync();

             while (saving)
             {
                 System.Threading.Thread.Sleep(5);
             }
             return true;
        }




        /// <summary>
        /// Load Data into local _data
        /// </summary>
        /// <returns>bool type true if success</returns>
        private bool LoadLOBData()
        {
            ////	Reset
            _items = new List<MAttachmentEntry>();
            //// Get binaryData from DB
            //byte[] data = GetBinaryData();

            //// if no data, then return
            //if (data == null)
            //    return true;

           // log.Fine("ZipSize=" + data.Length);
            //if (data.Length == 0)
            //    return true;

            ////	Old Format - single file
            //if (!ZIP.Equals(GetTitle()))
            //{
            //    _items.Add(new MAttachmentEntry(GetTitle(), data, 1));
            //    return true;
            //}
            //// convert byte[] to byte[] data
            //byte[] sdata = ConvertTobyte(data);
            //try
            //{
            //    ByteArrayInputStream inBt = new ByteArrayInputStream(sdata);
            //    // initialize zip
            //    ZipInputStream zip = new ZipInputStream(inBt);
            //    // get next entry i.e. 1st entry in zip
            //    ZipEntry entry = zip.getNextEntry();
            //    // for every entry in zip
            //    while (entry != null)
            //    {
            //        // get file name
            //        string name = entry.getName();
            //        ByteArrayOutputStream outBt = new ByteArrayOutputStream();
            //        byte[] buffer = new byte[2048];
            //        int length = zip.read(buffer);
            //        while (length != -1)
            //        {
            //            // get data
            //            outBt.write(buffer, 0, length);
            //            length = zip.read(buffer);
            //        }
            //        //s
            //        byte[] sdataEntry = outBt.toByteArray();
            //        byte[] dataEntry = ConvertToByte(sdataEntry);

            //        log.Fine(name
            //        + " - size=" + dataEntry.Length + " - zip="
            //        + entry.getCompressedSize() + "(" + entry.getSize() + ") "
            //        + (entry.getCompressedSize() * 100 / entry.getSize()) + "%");


            //        // add the entry into _items list
            //        _items.Add(new MAttachmentEntry(name, dataEntry, _items.Count + 1));//silverlight comment
            //        //_items.Add(new MAttachmentEntry(_attchedFileName.GetName(), sdata, _items.Count + 1));//without zip
            //        // get next entry in zip
            //        entry = zip.getNextEntry();
            //    }
            //}
            //catch (Exception ex)
            //{
            //    log.Log(Level.SEVERE, "loadLOBData", ex);
            //    _items = null;
            //    return false;
            //}
            return true;
        }

        /// <summary>
        /// Convert byte[] to byte[]
        /// </summary>
        /// <param name="byteVar">byte[]</param>
        /// <returns>byte[]</returns>
        private byte[] ConvertToByte(byte[] byteVar)
        {
            //int iLen = byteVar.Length;
            //byte[] byteData = new byte[iLen];
            //for (int i = 0; i < iLen; i++)
            //{
            //    byteData[i] = (byte)byteVar[i];
            //}

            if (byteVar != null)
            {
                byte[] byteData = new byte[byteVar.Length];
                System.Buffer.BlockCopy(byteVar, 0, byteData, 0, byteVar.Length);

                return byteData;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Convert byte[] to byte[]
        /// </summary>
        /// <param name="byteVar">byte[]</param>
        /// <returns>byte[]</returns>
        private byte[] ConvertTobyte(byte[] byteVar)
        {
            if (byteVar != null)
            {
                //int len = byteVar.Length;
                //byte[] byteData = new byte[len];
                //for (int i = 0; i < len; i++)
                //{
                //    byteData[i] = (byte)byteVar[i];
                //}
                byte[] byteData = new byte[byteVar.Length];
                System.Buffer.BlockCopy(byteVar, 0, byteData, 0, byteVar.Length);

                return byteData;
            }
            else
            {
                return null;
            }
        }

    }
}

//namespace Sharpen.IO
//{
//    public class ByteArrayOutputStream :OutputStream
//    {
//        public ByteArrayOutputStream()
//            : base(new MemoryStream())
//        {
//        }

//        public ByteArrayOutputStream(int size)
//            : base(new MemoryStream(size))
//        {
//        }

//        public int Size()
//        {
//            return (int)Stream.Length;
//        }

//        public void WriteTo(OutputStream stream)
//        {
//            Stream.WriteTo(stream.UnderlyingStream);
//        }

//        public byte[] ToByteArray()
//        {
//            return Stream.ToArray();
//        }

//        private MemoryStream Stream
//        {
//            get { return (MemoryStream)UnderlyingStream; }
//        }
//    }
//}
